import useToast from '@/hooks/useToast';
import { useContext, useRef } from 'react';
import type {
  ICreateEditPostDraftBody,
  ICreateNewPostDraftBody,
  IUploadMessageSendFile,
  IUploadMessageSendFileBody,
  IUploadPostContent,
  IUploadPostContentBody,
  IUploadPostNewFile,
  IUploadPostNewFileBody,
  IUploadPostTemplateFile,
  IUploadPostTemplateFileBody,
} from '@/interfaces';
import { useMutation } from '@tanstack/react-query';
import type { TBody } from '@/types';
import {
  createEditPostDraft,
  createNewPostDraft,
  uploadMessageSendFile,
  uploadPostContent,
  uploadPostNewFile,
  uploadPostTemplateFile,
} from '@/services/api';
import { initEditor } from '@/lib/editor';
import Script from 'next/script';
import { AppContext } from '@/contexts/app';
import FileManager, {
  type TFileManagerTranslatedField,
} from '@/app/[locale]/file/file-manager';
import useModal from '@/hooks/useModal';
import { PostEditContext } from '@/contexts/post-edit';
import { useLocale } from 'use-intl';

export type TEditorDynamicTranslatedField = 'fileManager';

export default function EditorDynamic({
  id,
  onReadyCallback = () => {},
  translatedFields = {
    fileManager: '文件管理器',
  },
  fileManagerTranslatedFields,
  type = 'post',
}: {
  id?: number;
  onReadyCallback?: ({
    watchdog,
    editor,
  }: {
    watchdog: any;
    editor: any;
  }) => void;
  translatedFields?: Record<TEditorDynamicTranslatedField, any>;
  fileManagerTranslatedFields?: Record<TFileManagerTranslatedField, any>;
  type?: 'post' | 'message' | 'postTemplate' | 'section';
}) {
  const { showModal, hideModal } = useModal();
  const { show } = useToast();
  const editorElementRef = useRef<HTMLDivElement>(null);
  const context = useContext(AppContext);
  const metadata = context.metadata!;
  const isEdit = !!id;
  const { form } = useContext(PostEditContext);
  const locale = useLocale();

  const uploadPostContentMutation = useMutation(
    async (variables: TBody<IUploadPostContentBody>) => {
      return (await uploadPostContent(variables)) as IUploadPostContent;
    },
  );
  const uploadPostNewContentMutation = useMutation(
    async (variables: TBody<IUploadPostNewFileBody>) => {
      return (await uploadPostNewFile(variables)) as IUploadPostNewFile;
    },
  );
  const createNewPostDraftMutation = useMutation(
    async (variables: TBody<ICreateNewPostDraftBody>) => {
      await createNewPostDraft(variables);
    },
  );
  const createEditPostDraftMutation = useMutation(
    async (variables: TBody<ICreateEditPostDraftBody>) => {
      await createEditPostDraft(variables);
    },
  );
  const uploadPostTemplateFileMutation = useMutation(
    async (variables: TBody<IUploadPostTemplateFileBody>) => {
      return (await uploadPostTemplateFile(
        variables,
      )) as IUploadPostTemplateFile;
    },
  );
  const uploadMessageSendFileMutation = useMutation(
    async (variables: TBody<IUploadMessageSendFileBody>) => {
      return (await uploadMessageSendFile(variables)) as IUploadMessageSendFile;
    },
  );

  function onReady() {
    const element = editorElementRef.current;
    if (!element) {
      return;
    }

    const config: Record<string, any> = {
      onReadyCallback,
      ywFileUpload: {
        upload: async (file: File) => {
          try {
            let result;
            if (type === 'postTemplate' && id) {
              result = await uploadPostTemplateFileMutation.mutateAsync({
                id,
                data: {
                  file,
                },
              });
            } else if (type === 'message') {
              result = await uploadMessageSendFileMutation.mutateAsync({
                data: {
                  file,
                },
              });
            } else if (type === 'post') {
              if (isEdit && id) {
                result = await uploadPostContentMutation.mutateAsync({
                  id,
                  data: {
                    file,
                  },
                });
              } else {
                result = await uploadPostNewContentMutation.mutateAsync({
                  data: {
                    file,
                  },
                });
              }
            } else if (type === 'section') {
              result = await uploadPostNewContentMutation.mutateAsync({
                data: {
                  file,
                },
              });
            } else {
              return Promise.reject(new Error('Unsupported operation'));
            }

            result.urls.default =
              metadata.env.APP_OSS_SERVER + result.urls.default;
            return result.urls;
          } catch (e) {
            if (type === 'postTemplate' && id) {
              uploadPostTemplateFileMutation.reset();
            } else if (type === 'message') {
              uploadMessageSendFileMutation.reset();
            } else if (type === 'post') {
              if (isEdit && id) {
                uploadPostContentMutation.reset();
              } else {
                uploadPostNewContentMutation.reset();
              }
            } else if (type === 'section') {
              uploadPostNewContentMutation.reset();
            }

            show({
              type: 'DANGER',
              message: e,
            });

            throw e;
          }
        },
        abort: () => {},
      },
      ywFileBox: {
        onOpen: (options: { onClose: () => void; onSelect: () => void }) => {
          const mid = showModal({
            title: translatedFields.fileManager,
            centered: false,
            content: (
              <FileManager
                id={id}
                type="post"
                options={options}
                onCloseModal={() => {
                  hideModal(mid);
                }}
                translatedFields={fileManagerTranslatedFields}
              />
            ),
            onHidden: options.onClose,
            isShowFooter: false,
            extraLarge: true,
          });
        },
      },
    };

    if (type === 'post') {
      config.autosave = {
        waitingTime: 5000,
        save: async () => {
          try {
            const { name, overview, content } = form;
            const data = {
              name,
              overview,
              content,
            };

            if (!name && !overview && !content) {
              return Promise.resolve();
            }

            if (isEdit) {
              await createEditPostDraftMutation.mutateAsync({
                id,
                data,
              });
            } else {
              await createNewPostDraftMutation.mutateAsync({
                data,
              });
            }

            return Promise.resolve();
          } catch (e) {
            if (isEdit) {
              createEditPostDraftMutation.reset();
            } else {
              createNewPostDraftMutation.reset();
            }

            show({
              type: 'DANGER',
              message: e,
            });

            throw e;
          }
        },
      };
    }

    initEditor({
      element,
      config,
    });
  }

  function onError(e: any) {
    show({
      type: 'DANGER',
      message: e,
    });
  }

  return (
    <>
      <div ref={editorElementRef}></div>
      <Script
        src={
          locale === 'en' ? '/lib/ckeditor.en.min.js' : '/lib/ckeditor.min.js'
        }
        onReady={onReady}
        onError={onError}
      />
    </>
  );
}
